//! @file   lc_basic_string.h
//! @brief  
//! @author Sayan Chaliha
//! @date   September, 2011
//!
//! 
#ifndef _LC_BASIC_STRING_H
#define _LC_BASIC_STRING_H

#include "libcyan_internal.h"
#include "lc_forward_decl.h"
#include "lc_types.h"
#include "lc_char_traits.h"
#include "lc_iterator.h"
#include "lc_normal_iterator.h"
#include "lc_atomic_word.h"
#include "lc_object.h"

namespace cyan {
#ifdef DEBUG
  template <typename C>
  inline void assertStringLengthHelper_(const C* str, Size n) {
    assertNotNull(str + n);
    assertGtOrEq(CharTraits<C>::length(str), n);
  }
# define assertStringLength(str, n)   assertStringLengthHelper_((str), (n))
#else
# define assertStringLength(str, n)
#endif /* DEBUG */

  template <typename C, typename T>
  class CYAN_API BasicString : public Object {
  public:
    typedef T                                           TraitsType;
    typedef typename TraitsType::ValueType              ValueType;
    typedef typename TraitsType::SizeType               SizeType;
    typedef PtrDiff                                     DifferenceType;
    typedef C&                                          Reference;
    typedef const C&                                    ConstReference;
    typedef C*                                          Pointer;
    typedef const C*                                    ConstPointer;
    typedef NormalIterator<Pointer, BasicString>        Iterator;
    typedef NormalIterator<ConstPointer, BasicString>   ConstIterator;

    static const SizeType npos = SizeType(-1);

    BasicString();
    BasicString(const BasicString&);
    BasicString(const BasicString&, SizeType, SizeType = npos);
    BasicString(ConstPointer, SizeType);
    BasicString(ConstPointer);
    BasicString(SizeType, ValueType = Rep::terminal);
    virtual ~BasicString();

    SizeType        length()        const;
    SizeType        size()          const;
    SizeType        maximumSize()   const;
    SizeType        capacity()      const;
    Bool            isEmpty()       const;
    void            clear();

    Iterator        begin();
    ConstIterator   begin()         const;
    Iterator        end();
    ConstIterator   end()           const;

    Reference       front();
    ConstReference  front()         const;
    Reference       back();
    ConstReference  back()          const;
    BasicString&    pushFront(ValueType c);
    BasicString&    pushBack(ValueType c);
    BasicString&    popFront();
    BasicString&    popBack();

    BasicString&    assign(const BasicString& str);
    BasicString&    assign(ConstPointer str, SizeType length);
    BasicString&    assign(ConstPointer str);
    BasicString&    assign(ValueType c, SizeType n = 1);
    BasicString&    assign(const BasicString& str, SizeType pos,
                        SizeType length = npos);
    BasicString&    formattedAssign(ConstPointer format, ...);

    BasicString&    prepend(const BasicString& str);
    BasicString&    prepend(ConstPointer str, SizeType length);
    BasicString&    prepend(ConstPointer str);
    BasicString&    prepend(ValueType c, SizeType n = 1);
    BasicString&    prepend(const BasicString& str, SizeType pos,
                        SizeType length = npos);
    BasicString&    formattedPrepend(ConstPointer format, ...);

    BasicString&    append(const BasicString& str);
    BasicString&    append(ConstPointer str, SizeType length);
    BasicString&    append(ConstPointer str);
    BasicString&    append(ValueType c, SizeType n = 1);
    BasicString&    append(const BasicString& str, SizeType pos,
                        SizeType length = npos);
    BasicString&    formattedAppend(ConstPointer format, ...);

    void            reserve(SizeType res = 0);

    Int             compare(const BasicString& str) const;
    Int             compare(ConstPointer str)       const;

    Int32           toInt32()   const;
    Int64           toInt64()   const;
    Double          toDouble()  const;

    SizeType        find(ConstPointer, SizeType, SizeType)  const;
    SizeType        find(const BasicString&, SizeType = 0)  const;
    SizeType        find(ConstPointer, SizeType = 0)        const;
    SizeType        find(ValueType, SizeType = 0)           const;
    BasicString&    findAndReplace(SizeType, ConstPointer, ConstPointer);
    BasicString&    findAndReplace(ConstPointer, ConstPointer);

    BasicString&    stripLChar(ValueType);
    BasicString&    stripRChar(ValueType);
    BasicString&    stripWhiteSpace();

    BasicString     substring(SizeType, SizeType = npos)    const;
    ConstPointer    toCString()                             const;
    String          toString()                              const;
    WString         toWString()                             const;

    virtual UInt32  hashCode()                              const;

    Bool            operator ==(ConstPointer str)           const;
    Bool            operator ==(const BasicString& str)     const;
    Bool            operator !=(ConstPointer str)           const;
    Bool            operator !=(const BasicString& str)     const;
    ConstReference  operator [](SizeType pos)               const;
    Reference       operator [](SizeType pos);
                    operator ConstPointer()                 const;
    BasicString&    operator =(const BasicString& str);
    BasicString&    operator =(ConstPointer str);

  private:
    mutable Pointer referenceData_;

    struct CYAN_HIDDEN RepBase {
      SizeType    length;
      SizeType    capacity;
      AtomicWord  referenceCount;
    };

    struct CYAN_HIDDEN Rep : public RepBase {
      static const SizeType   maximumSize;
      static const ValueType  terminal;
      static SizeType         emptyRepStorage[];

      static Rep&       emptyRep();
      static Rep*       create(SizeType, SizeType);

      Bool              isLeaked()        const;
      Bool              isShared()        const;

      void              setLeaked();
      void              setSharable();
      void              setLengthAndSharable(SizeType);

      Pointer           data();
      Pointer           grab();
      Pointer           copy();
      Pointer           clone(SizeType = 0);

      void              dispose();
      void              destroy();
    };

    Pointer       CYAN_HIDDEN     data()          const;
    Pointer       CYAN_HIDDEN     data(Pointer);
    Rep*                          rep()           const;
    static Rep&                   emptyRep();

    Iterator      CYAN_HIDDEN     iBegin()        const;
    Iterator      CYAN_HIDDEN     iEnd()          const;
    void          CYAN_HIDDEN     leak();
    void          CYAN_HIDDEN     leakHard();
    SizeType      CYAN_HIDDEN     check(SizeType, const Char*)  const;
    void          CYAN_HIDDEN     checkLength(SizeType, SizeType, const Char*);
    SizeType      CYAN_HIDDEN     limit(SizeType, SizeType)     const;
    Bool          CYAN_HIDDEN     disjunct(ConstPointer)        const;

    static void   CYAN_HIDDEN     copy(Pointer, ConstPointer, SizeType);
    static void   CYAN_HIDDEN     move(Pointer, ConstPointer, SizeType);
    static void   CYAN_HIDDEN     assign(Pointer, SizeType, ValueType);
    static Int    CYAN_HIDDEN     compare(SizeType, SizeType);

    template <typename I>
    static void   CYAN_HIDDEN     copyChars(Pointer, I, I);
    static void   CYAN_HIDDEN     copyChars(Pointer, Iterator, Iterator);
    static void   CYAN_HIDDEN     copyChars(Pointer, ConstIterator,
                                      ConstIterator);
    static void   CYAN_HIDDEN     copyChars(Pointer, ConstPointer,
                                      ConstPointer);
    static void   CYAN_HIDDEN     copyChars(Pointer, Pointer, Pointer);

    static Pointer  CYAN_HIDDEN   construct(SizeType, ValueType);
    template <typename I>
    static Pointer  CYAN_HIDDEN   construct(I, I, InputIteratorTag);
    template <typename I>
    static Pointer  CYAN_HIDDEN   construct(I, I, ForwardIteratorTag);

    void          CYAN_HIDDEN     mutate(SizeType, SizeType, SizeType);
    BasicString&                  replaceSafe(SizeType, SizeType,
                                      ConstPointer, SizeType);
    static void   CYAN_HIDDEN     sprintfHelper(Pointer, SSize&,
                                      ConstPointer, va_list);
  };

  template <typename C, typename T>
  Bool CYAN_API operator ==(typename BasicString<C, T>::ConstPointer,
      const BasicString<C, T>&);

  template <typename C, typename T>
  Bool CYAN_API operator !=(typename BasicString<C, T>::ConstPointer,
      const BasicString<C, T>&);
}

#endif /* _LC_BASIC_STRING_H */
